var Socket = require("socket").Socket;
var Buffer = require("binary").Buffer;

/**
 * Class: FileFoldersServer
 */

/**
 * Method: Constructor
 */
function FileFoldersServer(rr)
{
	this.rr=rr;
}

/**
 * Method: init
 */
FileFoldersServer.prototype.init=function()
{
	this.server_socket=new Socket(Socket.PF_INET, Socket.SOCK_STREAM, Socket.IPPROTO_TCP);
	this.server_socket.setOption(Socket.SO_REUSEADDR, true);
	this.server_socket.bind(this.rr.site.file_folders_server.address,this.rr.site.file_folders_server.port);
	this.server_socket.listen(10);
	this.clients=[];
	this.cache={};
}

/**
 * Method: remove_client_by_socket
 *		Removing client connection with given socket
 */
FileFoldersServer.prototype.remove_client_by_socket=function(sock)
{
//	system.stdout.writeLine("this.clients.length="+this.clients.length);
	this.clients=this.clients.filter(function(clt) { return clt.socket!==sock; });
//	system.stdout.writeLine("this.clients.length="+this.clients.length);
	sock.close();
}

FileFoldersServer.prototype.work=function()
{
	while(1) {
		// Добавляем в check_sockets все сокеты которые надо проверить что с ними что-то произошло
		var check_sockets=[this.server_socket];
		for (var i=0;i<this.clients.length;i++) check_sockets.push(this.clients[i].socket);

		var length_before=check_sockets.length;
		// Проверяем что кто-то из сокетов что-то хочет
		var result=Socket.select(check_sockets,[],[],1000);
		if (!result) continue;
		if (check_sockets.length) system.stdout.writeLine("work() - check_sockets.length="+check_sockets.length+" after select, was "+length_before+" before");

		// Идем по всем сокетам в которых что-то произошло
		for (var i=0;i<check_sockets.length;i++) {
			var s=check_sockets[i];
			if (s===this.server_socket) {// Это сервер - делаем accept
				this.clients.push(new FileFoldersClient(this.server_socket.accept(),this));
			} else {
				for (var j=0;j<this.clients.length;j++) {
					var clt=this.clients[j];
					if (!(clt.socket===s)) continue;
					if (!clt.work()) continue;
					this.remove_client_by_socket(clt.socket);
				}
			}
		}
	}
}

FileFoldersServer.prototype.get_ff=function(is_diskpath,ff_id)
{
	if (this.cache[is_diskpath+","+ff_id]) return this.cache[is_diskpath+","+ff_id];
	system.stdout.writeLine("Initializing cache");
	return this.cache[is_diskpath+","+ff_id]=this.rr.F("Files","file_folder_path",ff_id,is_diskpath,true);
}

/**
 * Class: FileFoldersClient
 */
/**
 * Method: Constructor
 */
function FileFoldersClient(socket,server)
{
	this.socket=socket;
	this.server=server;
}

/**
 * Method: work
 *		Makes some work with client socket
 * Returns:
 *		typeof Boolean		- returns true if something bad has happened and client is due to close 
 */
FileFoldersClient.prototype.work=function()
{
	// GETTING most 5000 bytes
	var buffer = this.socket.receive(5000);
	if (!buffer) return 1;
	if (buffer.length==0) return 1;

	var oldlength;
	if (this.buffer) {
		oldlength=this.buffer.length;
		var b=new Buffer(this.buffer.length+buffer.length);
		b.copyFrom(this.buffer,0,0,this.buffer.length);
		b.copyFrom(buffer,0,this.buffer.length,this.buffer.length+buffer.length);
		this.buffer=b;
	} else {
		this.buffer=buffer;
		oldlength=0;
	}
	system.stdout.write("[");
	for (var i=0;i<this.buffer.length;i++) system.stdout.write(" "+this.buffer[i]);
	system.stdout.write("]\n");
	var pos=0;
	var start=0;
	while (pos<this.buffer.length) {
		if (this.buffer[pos]==44) {// ','
			var is_diskpath=(this.buffer[start]==48)?0:1;
			var ff_id=this.buffer.toString("ASCII",start+2,pos);
			this.answer(is_diskpath,ff_id);
			start=pos+1;
		}
		pos++;
	}
	if (start) {
		b=new Buffer(this.buffer.length-start);
		b.copyFrom(this.buffer,start,0,this.buffer.length-start);
		this.buffer=b;
	}
	return 0;
}

FileFoldersClient.prototype.answer=function(is_diskpath,ff_id)
{
	var ret=this.server.get_ff(is_diskpath,ff_id);
	system.stdout.writeLine("answer("+is_diskpath+","+ff_id+")="+ret);
	this.socket.send(ret+",");
}


exports.add=[{
	_type:'functions',
	_section:'Daemons',

	file_folders_server: function() {
		var ff=new FileFoldersServer(this);
		ff.init();
		ff.work();
	}

}];
